package NWish.properties
{
	import NWish.Logger;
	import NWish.Misc;
	import NWish.NWEvent;
	import NWish.json.Json;
	import NWish.json.OrderDict;
	
	import NWish.Interface.ILogger;
	
	import away3d.containers.Scene3D;
	import away3d.entities.Mesh;
	
	import flash.geom.ColorTransform;
	import flash.geom.Vector3D;
	
	
	public class Properties
	{
		protected var _app;
		
		private var _propertieKeys : Array = [];
		private var _propertieKeys_read : Array = [];
		private var _propertieKeys_save : Array = [];
		
		static public const readMark:String = '#';
		static public const priorityMask:String = ':@';
		
		//static private var _typeMap = new Object();
		
		
		public function Properties(app)
		{
			_app = app;
		}
		
		
		public function get fileSystem()
		{
			if(_app)
				return _app.getPlugin('FileSystem');
		}
		
		public function get scene()
		{
			if(_app)
				return _app.getPlugin('Away3d').scene;
		}
		
		public function getObject3d(name)
		{
			var s = scene;
			if(s)
			{
				return Misc.getChildByNameInScene(name,s);
			}
		}
		
		//
		public function toString()
		{
			throw new Error();
		}
		public function get type()
		{
			throw new Error();
		}
		public function newType(scene,dict)
		{
			if(scene == null && dict == null)
				return new type();
			else if(scene)
				return new type();
			else
				throw new Error();
		}
		public function get createEnable()
		{
			return false;
		}
		public function get multiCreateEnable()
		{
			return false;
		}
		public function get needToNotifyCreateEvent()
		{
			return true;
		}
		public function get saveChildren()
		{
			return true;
		}
		
		public function isClass(obj)
		{
			return Misc.isClass(obj,type);
		}
		
		//
		public function addPropertieKeys(title,keys:Array)
		{
			if(title == null)
				_propertieKeys.push(keys);
			else
				_propertieKeys.push(title,keys);
		}
		public function addPropertieKeys_read(title,keys:Array)
		{
			if(title == null)
				_propertieKeys_read.push(keys);
			else
				_propertieKeys_read.push(title,keys);
		}
		public function addPropertieKeys_save(title,keys:Array)
		{
			if(title == null)
				_propertieKeys_save.push(keys);
			else
				_propertieKeys_save.push(title,keys);
		}
		
		/*static public function addType(name,type,propertiesType)
		{
			if(_typeMap[name] is Class)
				throw new Error();
			
			_typeMap[name] = {type:type,proType:propertiesType};
		}*/
		
		//
		public function get propertieKeys()
		{
			return _propertieKeys;
		}
		
		public function get propertieKeys_read()
		{
			return _propertieKeys_read;
		}
		
		//
		public function propertiesToDict(obj,dict:OrderDict,read_only = false,saving = false)
		{
			if(read_only == false)
			{
				var b = false;
				for each (var ks in _propertieKeys)
				{
					if(ks is String)
					{
						if(saving)
							continue;
						
						if(b)
							_title(ks,dict);
						else
						{
							b = true;
							dict.push(readMark + ks, '');
						}
					}
					else if(ks is Array)
					{
						for each(var k in ks)
						{
							if(k is String)
							{
								dict.push(k, obj[k]);
							}
							else
							{
								k.propertiesToDict(obj,dict,read_only,saving);
							}
						}
					}
					else
						throw new Error();
				}
			
				if(saving)
				{
					for each (var ks in _propertieKeys_save)
					{
						if(ks is String)
						{
							/*if(b)
								_title(ks,dict);
							else
							{
								b = true;
								dict.push(readMark + ks, '');
							}*/
						}
						else if(ks is Array)
						{
							for each(var k in ks)
							{
								if(k is String)
								{
									dict.push(k, obj[k]);
								}
								else
								{
									k.propertiesToDict(obj,dict,read_only,saving);
								}
							}
						}
						else
							throw new Error();
					}
				}
			}
			else
			{
				for each (var ks in _propertieKeys_read)
				{
					if(ks is String)
					{
						_title(ks + ' read only',dict);
						//dict.push(k, '');
					}
					else if(ks is Array)
					{
						for each(var k in ks)
						{
							if(k is String)
							{
								dict.push(readMark + k, obj[k]);
							}
							else
							{
								k.propertiesToDict(obj,dict,read_only,saving);
							}
						}
					}
					else
						throw new Error();
				}
			}
		}
		
		public function dictToProperties(dict,obj,scene:Scene3D,isloading)
		{
			for each (var ks in _propertieKeys)
			{
				if(ks is String)
				{
					//_title(ks,dict);
					//dict.push(k, '');
				}
				else if(ks is Array)
				{
					for each(var k in ks)
					{
						if(k is String)
						{
							if(obj.hasOwnProperty(k) == false)
							{
								ILogger.log('Can not find the key[' + k + '] info in object!',obj);
								continue;
							}
							
							if(obj[k] is Vector3D)
							{
								var v = dict[k];
								if(v)
									obj[k] = new Vector3D(v.x, v.y, v.z);
							}
							/*else if(obj[k] is ColorTransform)
							{
								var ct = dict[k];
								if(ct)
									obj[k] = new ColorTransform
										( ct.alphaMultiplier
										, ct.alphaOffset 
										, ct.blueMultiplier
										, ct.blueOffset
										//, ct.color
										, ct.greenMultiplier
										, ct.greenOffset 
										, ct.redMultiplier
										, ct.redOffset
										);
							}*/
							else
							{
								if(dict.hasOwnProperty(k))
								{
									var p = dict[k];
									obj[k] = p;
								}
								else
									ILogger.log('Can not find the key[' + k + '] info!',obj);
							}
						}
						else
						{
							k.dictToProperties(dict,obj,scene,isloading);
						}
					}
				}
				else
					throw new Error();
			}
		}
		
		//
		protected function _title(class_name,dict:OrderDict)
		{
			dict.push('#_spaceline_' + readMark + class_name, '');
		}
		
		/*protected function _spaceLine1(class_name,dict:OrderDict)
		{
		dict.push('#_spacelinebegin_' + class_name, '#_end_');
		}*/
		
		
		private var _currObj;
		public function getJSON(o/*,subMesh = null,scene:Scene3D*/):String
		{
			var obj;
			if(o)
				obj = o;
			else if(_currObj)
				obj = _currObj;
			else
			{
				//obj = newType(scene,null);
				obj = newType(null,null);
				if(obj == null)
					return null;
				_currObj = obj;
			}
			
			var dict = new OrderDict();
			propertiesToDict(obj,dict);
			propertiesToDict(obj,dict,true);
			
			
			var s:String = Json.encode( dict );
			
			return s;
		}
		
		static private var _multiCreateStr:String = readMark + 'Multi Create';
		public function create(properties:String,scene:Scene3D)
		{
			if(scene == null)
			{
				ILogger.log('please to create a view first or click MenuBar->File->New!');
				return;
			}
			
			var dict:Object = Json.decode( properties,false );
			
			var str_pos = properties.search(_multiCreateStr);
			
			if(str_pos == -1)
			{
				var obj = newType(scene,dict);
				if(obj == null)
					return null;
				
				dictToProperties(dict,obj,scene,false);
				
				if(obj.hasOwnProperty('initialize'))
					obj.initialize();
				
				return obj;
			}
			else
			{
				var mc = properties.substr(str_pos + _multiCreateStr.length);
				var mc_dict:Object = Json.decode( mc,false );
				
				var obList = [];
				for(var x = 0; x < mc_dict.x_num; ++x)
				for(var y = 0; y < mc_dict.y_num; ++y)
				for(var z = 0; z < mc_dict.z_num; ++z)
				{
					var obj = newType(scene,dict);
					if(obj == null)
						return null;
					
					dictToProperties(dict,obj,scene,false);
					
					if(obj.hasOwnProperty('initialize'))
						obj.initialize();
					
					obj.x += x * mc_dict.x_distance;
					obj.y += y * mc_dict.y_distance;
					obj.z += z * mc_dict.z_distance;
					
					obList.push(obj);
				}
				return obList;//or return first
			}
		}
		
		public function createFromDict(dict:Object,scene:Scene3D)
		{
			var obj = newType(scene,dict);
			if(obj == null)
				return null;
			
			dictToProperties(dict,obj,scene,false);
			
			if(obj.hasOwnProperty('initialize'))
				obj.initialize();
			
			return obj;
		}
		
		public function apply(obj, properties:String/*, subMesh*/, scene:Scene3D)
		{
			var dict:Object = Json.decode( properties,false );
			
			for(var k:String in dict)
			{
				if(k.search(readMark) != -1)
					dict[k] = null;
			}
			
			dictToProperties(dict,obj,scene,false);
			
			if(obj.hasOwnProperty('initialize'))
				obj.initialize();
		}
		
		protected function index(obj)
		{
			return '';
		}
		public function save(obj,toDict:OrderDict,subPropertiesType:Array = null,isChild = false)
		{
			var dict = new OrderDict();
			propertiesToDict(obj,dict,false,true);
			
			var child_str = isChild ? ':child':'';
			toDict.push(toString() + index(obj) + child_str, dict);
			
			for each(var sp in subPropertiesType)
			{
				if(sp is Class)
					new sp().save(obj,dict);
				else
					sp.save(obj,dict);
			}
			
			return dict;
		}
		
		
		public function load(dict,obj,scene,subPropertiesType:Array = null)
		{
			if(scene == null)
			{
				ILogger.log('please to create a view first or click MenuBar->File->New!');
				return;
			}
			
			if((obj is type) == false)
				obj = null;
			
			return load1(dict,obj,scene,subPropertiesType)
		}
		
		protected function load1(dict,obj,scene,subPropertiesType:Array = null)
		{
			//
			//trace(toString());
			var child_dict = dict[toString()];
			
			if(child_dict == null)
			{
				for (var k:String in dict)
				{
					if(k.search(toString()) != -1)
					{
						if(k.search(':') != -1)
						{
							child_dict = dict[k];
							break;
						}
					}
				}
			}
			
			
			//
			if(obj == null)
			{
				obj = newType(scene,child_dict);
				
				if(obj == null)
					return;
				
				//
				try{obj.name = child_dict.name;}
				catch(e){throw new Error();}
				
				if(_app && needToNotifyCreateEvent)
					_app.dispatchEvent(new NWEvent(NWEvent.CREATE_OBJECT,obj));
			}
			
			//
			if(child_dict == null)
			{
				ILogger.log('can not find type : ' + toString());
				return;
			}
			
			//
			dictToProperties(child_dict,obj,scene,true);
			
			//
			for each(var sp in subPropertiesType)
			{
				if(sp is Class)
					new sp().load(child_dict,obj,scene);
				else
					sp.load(child_dict,obj,scene);
			}
			
			if(obj.hasOwnProperty('initialize'))
				obj.initialize();
			
			//return [child_dict,obj];
			return obj;
		}
		public function getMultiCreateJson()
		{
			var dict:OrderDict = new OrderDict();
			
			dict.push('x_num',1);
			dict.push('y_num',1);
			dict.push('z_num',1);
			
			dict.push('x_distance',100);
			dict.push('y_distance',100);
			dict.push('z_distance',100);
			
			var s:String = Json.encode( dict );
			
			return '\n' + _multiCreateStr + s;
		}
		
	}
}







